package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.dto.*;
import com.leyou.item.entity.*;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.leyou.common.constants.MQConstants.ExchangeConstants.ITEM_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_DOWN_KEY;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_UP_KEY;

/**
 * @author 虎哥
 */
@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    private final CategoryService categoryService;
    private final BrandService brandService;
    private final SpuDetailService detailService;
    private final SkuService skuService;
    private final SpecParamService paramService;
    private final AmqpTemplate amqpTemplate;

    public SpuServiceImpl(
            CategoryService categoryService, BrandService brandService, SpuDetailService detailService,
            SkuService skuService, SpecParamService paramService, AmqpTemplate amqpTemplate) {
        this.categoryService = categoryService;
        this.brandService = brandService;
        this.detailService = detailService;
        this.skuService = skuService;
        this.paramService = paramService;
        this.amqpTemplate = amqpTemplate;
    }

    @Override
    public PageDTO<SpuDTO> querySpuByPage(Integer page, Integer rows, Boolean saleable, Long categoryId, Long brandId, Long id) {
        // 健壮性判断
        int currentPage = Math.max(page, 1);
        int size = Math.min(rows, 100);
        // 分页查询
        Page<Spu> info = query()
                .eq(saleable != null, "saleable", saleable)
                .eq(categoryId != null, "cid3", categoryId)
                .eq(brandId != null, "brand_id", brandId)
                .eq(id != null, "id", id)
                .page(new Page<>(currentPage, size));
        // 解析分页结果
        List<Spu> list = info.getRecords();
        List<SpuDTO> dtoList = SpuDTO.convertEntityList(list);

        // 处理分类名称和品牌名称
        for (SpuDTO spuDTO : dtoList) {
            handleCategoryAndBrandName(spuDTO);
        }
        // 封装分页结果
        return new PageDTO<>(info.getTotal(), info.getPages(), dtoList);
    }

    @Override
    @Transactional
    public void saveGoods(SpuDTO spuDTO) {
        // 1.新增spu
        // 1.1.转换DTO
        Spu spu = spuDTO.toEntity(Spu.class);
        // 1.2.填写默认字段，默认下架
        spu.setSaleable(false);
        // 1.3.新增
        save(spu);

        Long spuId = spu.getId();

        // 2.新增spuDetail
        // 2.1.获取detail
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();
        // 2.2.转换
        SpuDetail detail = spuDetailDTO.toEntity(SpuDetail.class);
        // 2.3.添加id
        detail.setSpuId(spuId);

        detailService.save(detail);

        // 3.新增Sku
        // 3.1.获取sku
        List<SkuDTO> dtoList = spuDTO.getSkus();
        // 3.2.转换
        List<Sku> skuList = new ArrayList<>();
        for (SkuDTO skuDTO : dtoList) {
            Sku sku = skuDTO.toEntity(Sku.class);
            skuList.add(sku);
            // 3.3.补充默认字段
            sku.setSpuId(spuId);
            sku.setSaleable(false);
        }
        // 3.4.保存sku
        skuService.saveBatch(skuList, skuList.size());
    }

    @Override
    @Transactional
    public void updateSaleable(Long id, Boolean saleable) {
        // 1.修改spu的上下架
        Spu spu = new Spu();
        spu.setId(id);
        spu.setSaleable(saleable);
        boolean success = updateById(spu);
        if (!success) {
            throw new LyException(500, "更新失败或已经更新！");
        }
        // 2.修改sku的上下架 update tb_sku set saleable = false where spu_id = 1
        success = skuService.update()
                .set("saleable", saleable)
                .eq("spu_id", id).update();
        if (!success) {
            throw new LyException(500, "更新失败或已经更新！");
        }

        // 3.发送消息
        // 3.1.RoutingKey
        String routingKey = saleable ? ITEM_UP_KEY : ITEM_DOWN_KEY;
        // 3.2.发送
        amqpTemplate.convertAndSend(ITEM_EXCHANGE_NAME, routingKey, id);
    }

    @Override
    public SpuDTO queryGoodsById(Long id) {
        // 1.查询spu
        Spu spu = getById(id);
        if (spu == null) {
            throw new LyException(404, "商品spu不存在！");
        }
        SpuDTO spuDTO = new SpuDTO(spu);
        // 2.查询spuDetail
        SpuDetail detail = detailService.getById(id);
        if (detail == null) {
            throw new LyException(404, "商品spuDetail不存在！");
        }
        spuDTO.setSpuDetail(new SpuDetailDTO(detail));

        // 3.查询sku
        List<Sku> skuList = skuService.query().eq("spu_id", id).list();
        if (CollectionUtils.isEmpty(skuList)) {
            throw new LyException(404, "商品sku不存在！");
        }
        spuDTO.setSkus(SkuDTO.convertEntityList(skuList));

        // 4.查询spu的分类和品牌的名称
        handleCategoryAndBrandName(spuDTO);
        return spuDTO;
    }

    @Override
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {
        // 1.spu
        // 1.1.获取id
        Long spuId = spuDTO.getId();
        // 1.2.判断是否要修改
        if (spuId != null) {
            // 有spu数据，要修改.
            // 1.3.转换dto
            Spu spu = spuDTO.toEntity(Spu.class);
            spu.setSaleable(null);
            // 1.4.修改
            boolean success = updateById(spu);
            if (!success) {
                throw new LyException(500, "更新商品失败");
            }
        }
        // 2.spuDetail
        // 2.1.拿到detail
        SpuDetailDTO detailDTO = spuDTO.getSpuDetail();
        // 2.2.判断
        if (detailDTO != null && detailDTO.getSpuId() != null) {
            // 有数据，可以修改
            // 2.3.转换DTO
            SpuDetail detail = detailDTO.toEntity(SpuDetail.class);
            // 2.4.写
            boolean success = detailService.updateById(detail);
            if (!success) {
                throw new LyException(500, "更新商品失败");
            }
        }

        // 3.sku
        // 3.1.获取sku集合
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        // 3.2.判断是否要处理
        if (CollectionUtils.isEmpty(skuDTOList)) {
            return;
        }

        // 3.3.转换DTO
        // 3.4.分组，把包含saleable的放一组，将来删除；不包含saleable的放另一组，将来是新增或修改
        // 分组结果是一个map，key是布尔类型，true代表要删除的，false代表增或改的
        Map<Boolean, List<Sku>> skuMap = skuDTOList
                .stream()
                .map(skuDTO -> skuDTO.toEntity(Sku.class))
                .collect(Collectors.groupingBy(sku -> sku.getSaleable() != null));

        // 3.5.获取要删除的那一部分
        if (skuMap.containsKey(true)) {
            // 有需要删除的
            List<Sku> deleteSkuList = skuMap.get(true);
            // 删除
            List<Long> idList = deleteSkuList.stream().map(Sku::getId).collect(Collectors.toList());
            skuService.removeByIds(idList);
        }

        // 3.6.获取要新增或修改的那一部分
        if (skuMap.containsKey(false)) {
            // 获取要新增或修改的
            List<Sku> saveOrUpdateList = skuMap.get(false);
            // 新增或修改
            skuService.saveOrUpdateBatch(saveOrUpdateList);
        }
    }

    @Override
    public List<SpecParamDTO> querySpecValues(Long spuId, Boolean searching) {
        // 1.首先，我们根据商品id查询spuDetail
        SpuDetail detail = detailService.getById(spuId);

        // 2.解析spuDetail中的specification获取json
        String json = detail.getSpecification();

        // 3.解析json，得到其中的param的id
        // 3.1.把json反序列化为一个map，key是paramId，值是value
        Map<Long, Object> valueMap = JsonUtils.toMap(json, Long.class, Object.class);
        // 3.2.取ids
        Set<Long> ids = valueMap.keySet();

        // 4.根据得到param的id集合，查询SpecParam，基于searching过滤
        //	select * from tb_spec_param where id in (1,2,3) and searching = 1
        List<SpecParam> params = paramService.query()
                .in("id", ids).eq(searching != null, "searching", searching).list();

        // 5.把SpecParam与json串配对，组合出param及其value
        if (CollectionUtils.isEmpty(params)) {
            throw new LyException(404, "商品规格参数不存在！");
        }
        // 5.1.转DTO
        List<SpecParamDTO> paramDTOS = SpecParamDTO.convertEntityList(params);
        // 5.2.填value
        for (SpecParamDTO paramDTO : paramDTOS) {
            Object value = valueMap.get(paramDTO.getId());
            paramDTO.setValue(value);
        }
        return paramDTOS;
    }

    private void handleCategoryAndBrandName(SpuDTO spuDTO) {
        // 获取分类id
        List<Long> categoryIds = spuDTO.getCategoryIds();
        // 查询分类
        List<Category> categories = categoryService.listByIds(categoryIds);
        if (!CollectionUtils.isEmpty(categories)) {
            // 获取分类的名称
            // String names = categories.stream().map(Category::getName).collect(Collectors.joining("/"));
            StringBuilder sb = new StringBuilder();
            for (Category category : categories) {
                sb.append(category.getName()).append("/");
            }
            sb.deleteCharAt(sb.length() - 1);
            spuDTO.setCategoryName(sb.toString());
        }

        // 获取品牌id
        Long brandId = spuDTO.getBrandId();
        // 查询品牌
        Brand brand = brandService.getById(brandId);
        if (brand != null) {
            spuDTO.setBrandName(brand.getName());
        }
    }
}
